/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the files COPYING and Copyright.html.  COPYING can be found at the root   *
 * of the source code distribution tree; Copyright.html can be found at the  *
 * root level of an installed copy of the electronic HDF5 document set and   *
 * is linked from the top-level documents page.  It can also be found at     *
 * http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have          *
 * access to either file, you may request a copy from help@hdfgroup.org.     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdio.h>
#include <stdlib.h>

#include "H5private.h"
#include "h5tools.h"
#include "h5tools_dump.h"
#include "h5tools_utils.h"
#include "h5tools_ref.h"
#include "h5trav.h"
#include "h5dump_extern.h"
#include "h5dump_xml.h"

const char       *xmlnsprefix="hdf5:";

/*
 *  Alternative formating for data dumped to XML
 *  In general, the numbers are the same, but separators
 *  except spaces are not used.
 *
 *  Some of these are not used, as some kinds of data are
 *  dumped in completely new subroutines.
 *
 *  Some of this formatting may yet need to change.
 *
 *  This table only affects XML output.
 */
static h5tool_format_t         xml_dataformat = {
    0,              /*raw */

    "",             /*fmt_raw */
    "%d",           /*fmt_int */
    "%u",           /*fmt_uint */
    "%hhd",           /*fmt_schar */
    "%u",           /*fmt_uchar */
    "%d",           /*fmt_short */
    "%u",           /*fmt_ushort */
    "%ld",          /*fmt_long */
    "%lu",          /*fmt_ulong */
    NULL,           /*fmt_llong */
    NULL,           /*fmt_ullong */
    "%g",           /*fmt_double */
    "%g",           /*fmt_float */

    0,              /*ascii */
    0,              /*str_locale */
    0,              /*str_repeat */

    "",            /*arr_pre */
    "",             /*arr_sep */
    "",             /*arr_suf */
    1,              /*arr_linebreak */

    "",             /*cmpd_name */
    "",             /*cmpd_sep */
    "",             /*cmpd_pre */
    "",             /*cmpd_suf */
    "",             /*cmpd_end */

    " ",            /*vlen_sep */
    " ",            /*vlen_pre */
    "",             /*vlen_suf */
    "",             /*vlen_end */

    "%s",           /*elmt_fmt */
    "",             /*elmt_suf1 */
    " ",            /*elmt_suf2 */

    "",             /*idx_n_fmt */
    "",             /*idx_sep */
    "",             /*idx_fmt */

    80,             /*line_ncols *//*standard default columns */
    0,              /*line_per_line */
    "",             /*line_pre */
    "%s",           /*line_1st */
    "%s",           /*line_cont */
    "",             /*line_suf */
    "",             /*line_sep */
    1,              /*line_multi_new */
    "   ",          /*line_indent */

    1,              /*skip_first */

    1,              /*obj_hidefileno */
    " "H5_PRINTF_HADDR_FMT, /*obj_format */

    1,              /*dset_hidefileno */
    "DATASET %s ",  /*dset_format */
    "%s",           /*dset_blockformat_pre */
    "%s",           /*dset_ptformat_pre */
    "%s",           /*dset_ptformat */
     0,             /*array indices */
     0              /*escape non printable characters */
};


/* internal functions */
static int      xml_name_to_XID(const char *, char *, int , int );

/* internal functions used by XML option */
static void             xml_print_datatype(hid_t, unsigned);
static void             xml_print_enum(hid_t);
static int              xml_print_refs(hid_t, int);
static int              xml_print_strs(hid_t, int);
static char            *xml_escape_the_string(const char *, int);
static char            *xml_escape_the_name(const char *);

/*-------------------------------------------------------------------------
 * Function:    xml_dump_all_cb
 *
 * Purpose:     function callback called by H5Literate,
 *                displays everything in the specified object
 *
 * Return:      Success:        SUCCEED
 *
 *              Failure:        FAIL
 *
 * Programmer:  Ruey-Hsia Li
 *
 * Modifications:
 *  RMcG, November 2000
 *   Added XML support. Also, optionally checks the op_data argument
 *
 * PVN, May 2008
 *   Dump external links
 *
 *-------------------------------------------------------------------------
 */
static herr_t
xml_dump_all_cb(hid_t group, const char *name, const H5L_info_t *linfo, void UNUSED *op_data)
{
    hid_t       obj;
    herr_t      ret = SUCCEED;
    char       *obj_path = NULL;    /* Full path of object */
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t     curr_pos = 0;        /* total data element position   */

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    /* Build the object's path name */
    obj_path = (char *)HDmalloc(HDstrlen(prefix) + HDstrlen(name) + 2);
    if(!obj_path) {
        ret = FAIL;
        goto done;
    } 

    HDstrcpy(obj_path, prefix);
    HDstrcat(obj_path, "/");
    HDstrcat(obj_path, name);

    if(linfo->type == H5L_TYPE_HARD) {
        H5O_info_t  oinfo;

        /* Stat the object */
        if(H5Oget_info_by_name(group, name, &oinfo, H5P_DEFAULT) < 0) {
            error_msg("unable to get object information for \"%s\"\n", name);
            h5tools_setstatus(EXIT_FAILURE);
            ret = FAIL;
            goto done;
        } /* end if */

        switch(oinfo.type) {
        case H5O_TYPE_GROUP:
            if((obj = H5Gopen2(group, name, H5P_DEFAULT)) < 0)  {
                error_msg("unable to dump group \"%s\"\n", name);
                h5tools_setstatus(EXIT_FAILURE);
                ret = FAIL;
            }
            else {
                char *old_prefix; /* Pointer to previous prefix */

                /* Keep copy of prefix before iterating into group */
                old_prefix = HDstrdup(prefix);
                HDassert(old_prefix);

                /* Append group name to prefix */
                add_prefix(&prefix, &prefix_len, name);

                /* Iterate into group */
                dump_function_table->dump_group_function(obj, name);

                /* Restore old prefix name */
                HDstrcpy(prefix, old_prefix);
                HDfree(old_prefix);

                /* Close group */
                H5Gclose(obj);
            }
            break;

        case H5O_TYPE_DATASET:
            if((obj = H5Dopen2(group, name, H5P_DEFAULT)) >= 0) {
                if(oinfo.rc > 1 || hit_elink) {
                    obj_t  *found_obj;    /* Found object */

                    found_obj = search_obj(dset_table, oinfo.addr);

                    if(found_obj == NULL) {
                        ctx.indent_level++;

                        ctx.need_prefix = TRUE;
                        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                        /* Render the element */
                        h5tools_str_reset(&buffer);
                        h5tools_str_append(&buffer, "%s \"%s\" %s",
                                h5tools_dump_header_format->datasetbegin, name,
                                h5tools_dump_header_format->datasetblockbegin);
                        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                        error_msg("internal error (file %s:line %d)\n", __FILE__, __LINE__);

                        ctx.need_prefix = TRUE;
                        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                        /* Render the element */
                        h5tools_str_reset(&buffer);
                        if(HDstrlen(h5tools_dump_header_format->datasetblockend)) {
                            h5tools_str_append(&buffer, "%s", h5tools_dump_header_format->datasetblockend);
                            if(HDstrlen(h5tools_dump_header_format->datasetend))
                                h5tools_str_append(&buffer, " ");
                        }
                        if(HDstrlen(h5tools_dump_header_format->datasetend))
                            h5tools_str_append(&buffer, "%s", h5tools_dump_header_format->datasetend);
                        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                        ctx.indent_level--;

                        h5tools_setstatus(EXIT_FAILURE);
                        ret = FAIL;
                        H5Dclose(obj);
                        goto done;
                    } 
                    else if(found_obj->displayed) {
                        /* the XML version */
                        char *t_obj_path = xml_escape_the_name(obj_path);
                        char *t_prefix = xml_escape_the_name(HDstrcmp(prefix,"") ? prefix : "/");
                        char *t_name = xml_escape_the_name(name);
                        char *t_objname = xml_escape_the_name(found_obj->objname);
                        char dsetxid[100];
                        char parentxid[100];
                        char pointerxid[100];

                        /* Create OBJ-XIDs for the parent and object */
                        xml_name_to_XID(obj_path, dsetxid, (int)sizeof(dsetxid), 1);
                        xml_name_to_XID(prefix, parentxid, (int)sizeof(parentxid), 1);

                        ctx.need_prefix = TRUE;
                        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                        /* Render the element */
                        h5tools_str_reset(&buffer);
                        h5tools_str_append(&buffer, "<%sDataset Name=\"%s\" OBJ-XID=\"%s-%d\" "
                                "H5Path=\"%s\" Parents=\"%s\" "
                                "H5ParentPaths=\"%s\">",
                                xmlnsprefix,
                                t_name,                     /* Dataset Name */
                                dsetxid, get_next_xid(),    /* OBJ-XID */
                                t_obj_path,                 /* H5Path */
                                parentxid,                  /* Parents */
                                t_prefix);                  /* H5ParentPaths */
                        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                        xml_name_to_XID(found_obj->objname, pointerxid, (int)sizeof(pointerxid), 1);

                        ctx.indent_level++;

                        ctx.need_prefix = TRUE;
                        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                        /* Render the element */
                        h5tools_str_reset(&buffer);
                        h5tools_str_append(&buffer, "<%sDatasetPtr OBJ-XID=\"%s\" H5Path=\"%s\"/>",
                                xmlnsprefix,
                                pointerxid,t_objname);
                        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                        ctx.indent_level--;

                        ctx.need_prefix = TRUE;
                        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                        /* Render the element */
                        h5tools_str_reset(&buffer);
                        h5tools_str_append(&buffer, "</%sDataset>", xmlnsprefix);
                        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                        HDfree(t_name);
                        HDfree(t_obj_path);
                        HDfree(t_prefix);
                        HDfree(t_objname);

                        H5Dclose(obj);
                        goto done;
                    } 
                    else {
                        found_obj->displayed = TRUE;
                    }
                } /* end if */

                dump_function_table->dump_dataset_function(obj, name, NULL);
                H5Dclose(obj);
            } 
            else {
                error_msg("unable to dump dataset \"%s\"\n", name);
                h5tools_setstatus(EXIT_FAILURE);
                ret = FAIL;
            }
            break;

        case H5O_TYPE_NAMED_DATATYPE:
            if((obj = H5Topen2(group, name, H5P_DEFAULT)) < 0) {
                error_msg("unable to dump datatype \"%s\"\n", name);
                h5tools_setstatus(EXIT_FAILURE);
                ret = FAIL;
            } 
            else {
                dump_function_table->dump_named_datatype_function(obj, name);
                H5Tclose(obj);
            }
            break;

        default:
            error_msg("unknown object \"%s\"\n", name);
            h5tools_setstatus(EXIT_FAILURE);
            ret = FAIL;
        }
    } /* end if */
    else {
        char       *targbuf;

        switch(linfo->type) {
        case H5L_TYPE_SOFT:
            targbuf = (char *)HDmalloc(linfo->u.val_size);
            HDassert(targbuf);

            if(H5Lget_val(group, name, targbuf, linfo->u.val_size, H5P_DEFAULT) < 0) {
                error_msg("unable to get link value\n");
                h5tools_setstatus(EXIT_FAILURE);
                ret = FAIL;
            } 
            else {
                /* print the value of a soft link */
                /* XML */
                char linkxid[100];
                char parentxid[100];
                char targetxid[100];
                char *t_prefix = xml_escape_the_name(HDstrcmp(prefix,"") ? prefix : "/");
                char *t_name = xml_escape_the_name(name);
                char *t_targbuf = xml_escape_the_name(targbuf);
                char *t_obj_path = xml_escape_the_name(obj_path);
                char *t_link_path;
                int res;

                t_link_path = (char *)HDmalloc(HDstrlen(prefix) + linfo->u.val_size + 1);
                if(targbuf[0] == '/')
                    HDstrcpy(t_link_path, targbuf);
                else {
                    HDstrcpy(t_link_path, prefix);
                    HDstrcat(HDstrcat(t_link_path, "/"), targbuf);
                } /* end else */

                /* Create OBJ-XIDs for the parent and object */
                xml_name_to_XID(t_obj_path, linkxid, (int)sizeof(linkxid), 1);
                xml_name_to_XID(prefix, parentxid, (int)sizeof(parentxid), 1);

                /* Try to create an OBJ-XID for the object pointed to */
                res = xml_name_to_XID(t_link_path, targetxid, (int)sizeof(targetxid), 0);
                if (res == 0) {
                    /* target obj found */
                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sSoftLink LinkName=\"%s\" "
                            "OBJ-XID=\"%s\" "
                            "H5SourcePath=\"%s\" "
                            "TargetPath=\"%s\" TargetObj=\"%s\" "
                            "Parents=\"%s\" H5ParentPaths=\"%s\" />",
                            xmlnsprefix,
                            t_name,         /* LinkName */
                            linkxid,        /* OBJ-XID */
                            t_obj_path,     /* H5SourcePath */
                            t_targbuf,      /* TargetPath */
                            targetxid,      /* TargetObj */
                            parentxid,      /* Parents */
                            t_prefix);      /* H5ParentPaths */
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                } 
                else {
                    /* dangling link -- omit from xml attributes */
                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sSoftLink LinkName=\"%s\" "
                            "OBJ-XID=\"%s\" "
                            "H5SourcePath=\"%s\" "
                            "TargetPath=\"%s\"  "
                            "Parents=\"%s\" H5ParentPaths=\"%s\" />",
                            xmlnsprefix,
                            t_name,         /* LinkName */
                            linkxid,        /* OBJ-XID */
                            t_obj_path,     /* H5SourcePath */
                            t_targbuf,      /* TargetPath */
                            parentxid,      /* Parents */
                            t_prefix);      /* H5ParentPaths */
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                }

                HDfree(t_prefix);
                HDfree(t_name);
                HDfree(t_targbuf);
                HDfree(t_obj_path);
                HDfree(t_link_path);
            }

            HDfree(targbuf);
            break;

        case H5L_TYPE_EXTERNAL:
            targbuf = (char *)HDmalloc(linfo->u.val_size);
            HDassert(targbuf);

            if(H5Lget_val(group, name, targbuf, linfo->u.val_size, H5P_DEFAULT) < 0) {
                error_msg("unable to get external link value\n");
                h5tools_setstatus(EXIT_FAILURE);
                ret = FAIL;
            } /* end if */
            else {
                const char *filename;
                const char *targname;

                if(H5Lunpack_elink_val(targbuf, linfo->u.val_size, NULL, &filename, &targname) < 0) {
                    error_msg("unable to unpack external link value\n");
                    h5tools_setstatus(EXIT_FAILURE);
                    ret = FAIL;
                } /* end if */
                else {
                    char linkxid[100];
                    char parentxid[100];
                    char *t_name = xml_escape_the_name(name);
                    char *t_prefix = xml_escape_the_name(HDstrcmp(prefix,"") ? prefix : "/");
                    char *t_obj_path = xml_escape_the_name(obj_path);
                    char *t_filename = xml_escape_the_name(filename);
                    char *t_targname = xml_escape_the_name(targname);

                    /* Create OBJ-XIDs for the parent and object */
                    xml_name_to_XID(t_obj_path, linkxid, (int)sizeof(linkxid), 1);
                    xml_name_to_XID(prefix, parentxid, (int)sizeof(parentxid), 1);

                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sExternalLink LinkName=\"%s\" "
                            "OBJ-XID=\"%s\" "
                            "H5SourcePath=\"%s\" "
                            "TargetFilename=\"%s\"  "
                            "TargetPath=\"%s\"  "
                            "Parents=\"%s\" H5ParentPaths=\"%s\" />",
                            xmlnsprefix,
                            t_name,         /* LinkName */
                            linkxid,        /* OBJ-XID */
                            t_obj_path,     /* H5SourcePath */
                            filename,       /* TargetFilename */
                            targname,       /* TargetPath*/
                            parentxid,      /* Parents */
                            t_prefix);      /* H5ParentPaths */
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                    
                    HDfree(t_prefix);
                    HDfree(t_name);
                    HDfree(t_filename);
                    HDfree(t_targname);
                    HDfree(t_obj_path);
                } /* end else */
            } /* end else */
            HDfree(targbuf);
            break;

        default:
        {
            char linkxid[100];
            char parentxid[100];
            char *t_name = xml_escape_the_name(name);
            char *t_prefix = xml_escape_the_name(HDstrcmp(prefix,"") ? prefix : "/");
            char *t_obj_path = xml_escape_the_name(obj_path);

            /* Create OBJ-XIDs for the parent and object */
            xml_name_to_XID(t_obj_path, linkxid, (int)sizeof(linkxid), 1);
            xml_name_to_XID(prefix, parentxid, (int)sizeof(parentxid), 1);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sUserDefined LinkName=\"%s\" "
                    "OBJ-XID=\"%s\" "
                    "H5SourcePath=\"%s\" "
                    "LinkClass=\"%d\"  "
                    "Parents=\"%s\" H5ParentPaths=\"%s\" />",
                    xmlnsprefix,
                    t_name,             /* LinkName */
                    linkxid,            /* OBJ-XID */
                    t_obj_path,         /* H5SourcePath */
                    linfo->type,        /* LinkClass */
                    parentxid,          /* Parents */
                    t_prefix);          /* H5ParentPaths */
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            
            HDfree(t_prefix);
            HDfree(t_name);
            HDfree(t_obj_path);
        }
        break;
        } /* end switch */
    } /* end else */

done:

    h5tools_str_close(&buffer);

    if(obj_path)
        HDfree(obj_path);
    return ret;
}

/*
 * create a string suitable for and XML NCNAME.  Uses the
 * object reference to create the string.
 *
 *  'gen'; 0 - return null if not found
 *         1 - generate a fake entry and return fake id.
 */
int
xml_name_to_XID(const char *str , char *outstr, int outlen, int gen)
{
    haddr_t objno;      /* Object ID for object at path */

    if (outlen < 22) return 1;

    objno = ref_path_table_lookup(str);
    if (objno == HADDR_UNDEF) {
        if (HDstrlen(str) == 0) {
            objno = ref_path_table_lookup("/");
            if (objno == HADDR_UNDEF) {
                if (gen) {
                    objno = ref_path_table_gen_fake(str);
                    sprintf(outstr, "xid_"H5_PRINTF_HADDR_FMT, objno);
                    return 0;
                } 
                else {
                    return 1;
                }
            }
        } 
        else {
            if (gen) {
                objno = ref_path_table_gen_fake(str);
                sprintf(outstr, "xid_"H5_PRINTF_HADDR_FMT, objno);
                return 0;
            } 
            else {
                return 1;
            }
        }
    }

    sprintf(outstr, "xid_"H5_PRINTF_HADDR_FMT, objno);

    return(0);
}

static const char      *quote = "&quot;";
static const char      *amp = "&amp;";
static const char      *lt = "&lt;";
static const char      *gt = "&gt;";
static const char      *apos = "&apos;";

/*-------------------------------------------------------------------------
 * Function:    xml_escape_the_name
 *
 * Purpose:     Escape XML reserved chars in a name, so HDF5 strings
 *              and paths can be correctly read back in XML element.
 *
 * Return:      The revised string.
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static char                   *
xml_escape_the_name(const char *str)
{
    size_t      extra;
    size_t      len;
    size_t      i;
    const char *cp;
    char       *ncp;
    char       *rcp;
    size_t      ncp_len;

    if (!str)
        return NULL;

    cp = str;
    len = HDstrlen(str);
    extra = 0;

    for (i = 0; i < len; i++) {
        if (*cp == '\"')
            extra += (HDstrlen(quote) - 1);
        else if (*cp == '\'')
            extra += (HDstrlen(apos) - 1);
        else if (*cp == '<')
            extra += (HDstrlen(lt) - 1);
        else if (*cp == '>')
            extra += (HDstrlen(gt) - 1);
        else if (*cp == '&')
            extra += (HDstrlen(amp) - 1);

        cp++;
    }

    if (extra == 0)
        return HDstrdup(str);

    cp = str;
    ncp_len = len + extra + 1;
    rcp = ncp = (char *)HDmalloc(ncp_len);

    if (!ncp)
        return NULL;    /* ?? */

    for (i = 0; i < len; i++) {
        size_t esc_len;

        HDassert(ncp_len);
        if (*cp == '\'') {
            HDstrncpy(ncp, apos, ncp_len);
            esc_len = HDstrlen(apos);
        } 
        else if (*cp == '<') {
            HDstrncpy(ncp, lt, ncp_len);
            esc_len = HDstrlen(lt);
        } 
        else if (*cp == '>') {
            HDstrncpy(ncp, gt, ncp_len);
            esc_len = HDstrlen(gt);
        } 
        else if (*cp == '\"') {
            HDstrncpy(ncp, quote, ncp_len);
            esc_len = HDstrlen(quote);
        } 
        else if (*cp == '&') {
            HDstrncpy(ncp, amp, ncp_len);
            esc_len = HDstrlen(amp);
        } 
        else {
            *ncp = *cp;
            esc_len = 1;
        }
        ncp += esc_len;
        ncp_len -= esc_len;
        cp++;
    }

    *ncp = '\0';
    return rcp;
}

/*-------------------------------------------------------------------------
 * Function:    xml_escape_the_string
 *
 * Purpose:     Escape XML reserved chars in a string, so HDF5 strings
 *              and paths can be correctly read back in XML CDATA.
 *
 * Return:      The revised string.
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static char                   *
xml_escape_the_string(const char *str, int slen)
{
    size_t      extra;
    size_t      len;
    size_t      i;
    const char *cp;
    char       *ncp;
    char       *rcp;
    size_t      ncp_len;

    if (!str)
        return NULL;

    cp = str;

    if (slen < 0)
        len = HDstrlen(str);
    else
        len = slen;

    extra = 0;

    for (i = 0; i < len; i++) {
        if (*cp == '\\')
            extra++;
        else if (*cp == '\"')
            extra++;
        else if (*cp == '\'')
            extra += (HDstrlen(apos) - 1);
        else if (*cp == '<')
            extra += (HDstrlen(lt) - 1);
        else if (*cp == '>')
            extra += (HDstrlen(gt) - 1);
        else if (*cp == '&')
            extra += (HDstrlen(amp) - 1);
        cp++;
    }

    cp = str;
    ncp_len = len + extra + 1;
    rcp = ncp = (char *) HDcalloc(ncp_len, sizeof(char));

    if (ncp == NULL)
        return NULL; /* ?? */

    for (i = 0; i < len; i++) {
        size_t esc_len;

        HDassert(ncp_len);
        if (*cp == '\\') {
            *ncp++ = '\\';
            *ncp = *cp;
            esc_len = 1;
        }
        else if (*cp == '\"') {
            *ncp++ = '\\';
            *ncp = *cp;
            esc_len = 1;
        }
        else if (*cp == '\'') {
            HDstrncpy(ncp, apos, ncp_len);
            esc_len = HDstrlen(apos);
        }
        else if (*cp == '<') {
            HDstrncpy(ncp, lt, ncp_len);
            esc_len = HDstrlen(lt);
        }
        else if (*cp == '>') {
            HDstrncpy(ncp, gt, ncp_len);
            esc_len = HDstrlen(gt);
        }
        else if (*cp == '&') {
            HDstrncpy(ncp, amp, ncp_len);
            esc_len = HDstrlen(amp);
        }
        else {
            *ncp = *cp;
            esc_len = 1;
        }
        ncp += esc_len;
        ncp_len -= esc_len;
        cp++;
    }

    *ncp = '\0';
    return rcp;
}

/**
 **  XML print functions--these replace some functions in the
 **  h5tools.c suite.
 **/

/*-------------------------------------------------------------------------
 * Function:    xml_print_datatype
 *
 * Purpose:     Print description of a datatype in XML.
 *              Note:  this is called inside a <DataType> element.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static void
xml_print_datatype(hid_t type, unsigned in_group)
{
    char                   *mname;
    hid_t                   mtype;
    unsigned                nmembers;
    unsigned                ndims;
    unsigned                i;
    size_t                  size;
    hsize_t                 dims[H5DUMP_MAX_RANK];
    H5T_str_t               str_pad;
    H5T_cset_t              cset;
    hid_t                   super;
    H5T_order_t             ord;
    H5T_sign_t              sgn;
    size_t                  sz;
    size_t                  spos;
    size_t                  epos;
    size_t                  esize;
    size_t                  mpos;
    size_t                  msize;
    int                     nmembs;
    htri_t                  is_vlstr=FALSE;
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t     curr_pos = 0;        /* total data element position   */

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    if(!in_group && H5Tcommitted(type) > 0) {
        H5O_info_t oinfo;
        obj_t  *found_obj;    /* Found object */

        /* detect a shared datatype, output only once */
        H5Oget_info(type, &oinfo);
        found_obj = search_obj(type_table, oinfo.addr);

        if(found_obj) {
            /* This should be defined somewhere else */
            /* These 2 cases are handled the same right now, but
               probably will have something different eventually */
            char * dtxid = (char *)HDmalloc((size_t)100);

            xml_name_to_XID(found_obj->objname, dtxid, 100, 1);
            if (!found_obj->recorded) {
                /* 'anonymous' NDT.  Use it's object num.
                   as it's name.  */

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sNamedDataTypePtr OBJ-XID=\"/%s\"/>",
                        xmlnsprefix, dtxid);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            } 
            else {
                /* point to the NDT by name */
                char *t_objname = xml_escape_the_name(found_obj->objname);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sNamedDataTypePtr OBJ-XID=\"%s\" H5Path=\"%s\"/>",
                        xmlnsprefix, dtxid, t_objname);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                HDfree(t_objname);
            }
            HDfree(dtxid);
        } 
        else {
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- h5dump error: unknown committed type. -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            h5tools_setstatus(EXIT_FAILURE);
        }
    } 
    else {

        switch (H5Tget_class(type)) {
        case H5T_INTEGER:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level++;

            /* <hdf5:IntegerType ByteOrder="bo" Sign="torf" Size="bytes"/> */
            ord = H5Tget_order(type);
            sgn = H5Tget_sign(type);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sIntegerType ByteOrder=\"",xmlnsprefix);
            switch (ord) {
            case H5T_ORDER_LE:
                h5tools_str_append(&buffer, "LE");
                break;
            case H5T_ORDER_BE:
                h5tools_str_append(&buffer, "BE");
                break;
            case H5T_ORDER_VAX:
            default:
                h5tools_str_append(&buffer, "ERROR_UNKNOWN");
            }
            
            h5tools_str_append(&buffer, "\" Sign=\"");
            
            switch (sgn) {
            case H5T_SGN_NONE:
                h5tools_str_append(&buffer, "false");
                break;
            case H5T_SGN_2:
                h5tools_str_append(&buffer, "true");
                break;
            default:
                h5tools_str_append(&buffer, "ERROR_UNKNOWN");
            }
            
            h5tools_str_append(&buffer, "\" Size=\"");
            sz = H5Tget_size(type);
            h5tools_str_append(&buffer, "%lu", (unsigned long)sz);
            h5tools_str_append(&buffer, "\" />");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_FLOAT:
            /* <hdf5:FloatType ByteOrder="bo" Size="bytes"
               SignBitLocation="bytes"
               ExponentBits="eb" ExponentLocation="el"
               MantissaBits="mb" MantissaLocation="ml" /> */
            ord = H5Tget_order(type);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sFloatType ByteOrder=\"",xmlnsprefix);
            
            switch (ord) {
            case H5T_ORDER_LE:
                h5tools_str_append(&buffer, "LE");
                break;
            case H5T_ORDER_BE:
                h5tools_str_append(&buffer, "BE");
                break;
            case H5T_ORDER_VAX:
                h5tools_str_append(&buffer, "VAX");
                break;
            default:
                h5tools_str_append(&buffer, "ERROR_UNKNOWN");
            }
            
            h5tools_str_append(&buffer, "\" Size=\"");
            sz = H5Tget_size(type);
            h5tools_str_append(&buffer, "%lu", (unsigned long)sz);
            H5Tget_fields(type, &spos, &epos, &esize, &mpos, &msize);
            h5tools_str_append(&buffer, "\" SignBitLocation=\"%lu\" ", (unsigned long)spos);
            h5tools_str_append(&buffer, "ExponentBits=\"%lu\" ExponentLocation=\"%lu\" ", (unsigned long)esize, (unsigned long)epos);
            h5tools_str_append(&buffer, "MantissaBits=\"%lu\" MantissaLocation=\"%lu\" />", (unsigned long)msize, (unsigned long)mpos);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_TIME:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sTimeType />",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            h5tools_str_append(&buffer, "<!-- H5T_TIME: not yet implemented -->");
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_STRING:
            /* <hdf5:StringType Cset="cs" StrSize="chars" StrPad="pad" /> */
            size = H5Tget_size(type);
            str_pad = H5Tget_strpad(type);
            cset = H5Tget_cset(type);
            is_vlstr = H5Tis_variable_str(type);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sStringType Cset=\"",xmlnsprefix);
            if (cset == H5T_CSET_ASCII) {
                h5tools_str_append(&buffer, "H5T_CSET_ASCII\" ");
            } 
            else {
                h5tools_str_append(&buffer, "unknown_cset\" ");
            }
            if(is_vlstr)
                h5tools_str_append(&buffer, "StrSize=\"H5T_VARIABLE\" StrPad=\"");
            else
                h5tools_str_append(&buffer, "StrSize=\"%d\" StrPad=\"", (int) size);
            if (str_pad == H5T_STR_NULLTERM) {
                h5tools_str_append(&buffer, "H5T_STR_NULLTERM\"/>");
            } 
            else if (str_pad == H5T_STR_NULLPAD) {
                h5tools_str_append(&buffer, "H5T_STR_NULLPAD\"/>");
            } 
            else if (str_pad == H5T_STR_SPACEPAD) {
                h5tools_str_append(&buffer, "H5T_STR_SPACEPAD\"/>");
            } 
            else {
                h5tools_str_append(&buffer, "H5T_STR_ERROR\"/>");
            }
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_BITFIELD:
            /* <hdf5:BitfieldType ByteOrder="bo" Size="bytes"/> */
            ord = H5Tget_order(type);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sBitfieldType ByteOrder=\"",xmlnsprefix);
            
            switch (ord) {
            case H5T_ORDER_LE:
                h5tools_str_append(&buffer, "LE");
                break;
            case H5T_ORDER_BE:
                h5tools_str_append(&buffer, "BE");
                break;
            case H5T_ORDER_VAX:
            default:
                h5tools_str_append(&buffer, "ERROR_UNKNOWN");
            }
            
            size = H5Tget_size(type);
            h5tools_str_append(&buffer, "\" Size=\"%lu\"/>", (unsigned long)size);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_OPAQUE:
            /* <hdf5:OpaqueType Tag="tag" Size="bytes" /> */

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level++;
            mname = H5Tget_tag(type);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sOpaqueType Tag=\"%s\" ",xmlnsprefix, mname);
            H5free_memory(mname);
            size = H5Tget_size(type);
            h5tools_str_append(&buffer, "Size=\"%lu\"/>", (unsigned long)size);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_COMPOUND:
            /* recursively describe the components of a compound datatype */

            /* type of a dataset */
            nmembers = H5Tget_nmembers(type);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sCompoundType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            /* List each member Field of the type */
            /*   <hdf5:Field FieldName="name" > */
            /*   <hdf5:DataType > */
            ctx.indent_level++;
            dump_indent += COL;
            for (i = 0; i < nmembers; i++) {
                char *t_fname;

                mname = H5Tget_member_name(type, i);
                mtype = H5Tget_member_type(type, i);
                t_fname = xml_escape_the_name(mname);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sField FieldName=\"%s\">",xmlnsprefix, t_fname);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                H5free_memory(mname);
                HDfree(t_fname);
                dump_indent += COL;
                ctx.indent_level++;

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sDataType>",xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                ctx.indent_level++;
                dump_indent += COL;
                xml_print_datatype(mtype,0);
                dump_indent -= COL;
                ctx.indent_level--;

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "</%sDataType>",xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                dump_indent -= COL;
                ctx.indent_level--;

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "</%sField>",xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            }
            dump_indent -= COL;
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sCompoundType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_REFERENCE:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level++;
            /*  Only Object references supported at this time */

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sReferenceType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sObjectReferenceType />",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sReferenceType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_ENUM:
            /*  <hdf5:EnumType Nelems="ne" > list Name, values of enum */
            nmembs = H5Tget_nmembers(type);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            dump_indent += COL;
            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sEnumType Nelems=\"%d\">",xmlnsprefix, nmembs);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            xml_print_enum(type);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sEnumType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            dump_indent -= COL;
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sAtomicType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_VLEN:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sVLType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            super = H5Tget_super(type);
            dump_indent += COL;
            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sDataType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            dump_indent += COL;
            ctx.indent_level++;
            xml_print_datatype(super,0);
            dump_indent -= COL;
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sDataType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            dump_indent -= COL;
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sVLType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            H5Tclose(super);

            break;

        case H5T_ARRAY:
            /* Get array base type */
            super = H5Tget_super(type);

            /* Print lead-in */
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sArrayType Ndims=\"",xmlnsprefix);
            ndims = H5Tget_array_ndims(type);
            h5tools_str_append(&buffer, "%u\">", ndims);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            /* Get array information */
            H5Tget_array_dims2(type, dims);

            /* list of dimensions */
            ctx.indent_level++;
            for (i = 0; i < ndims; i++) {
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sArrayDimension DimSize=\"%u\"/>", xmlnsprefix, (int) dims[i]);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            }
            ctx.indent_level--;

            dump_indent += COL;
            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sDataType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            dump_indent += COL;
            ctx.indent_level++;
            xml_print_datatype(super,0);
            dump_indent -= COL;
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sDataType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            dump_indent -= COL;
            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sArrayType>",xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            /* Close array base type */
            H5Tclose(super);
            break;

        default:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- unknown datatype -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            h5tools_setstatus(EXIT_FAILURE);
            break;
        }
    } /* end else */

    h5tools_str_close(&buffer);
}

/*-------------------------------------------------------------------------
 * Function:    xml_dump_datatype
 *
 * Purpose:     Dump description of a datatype in XML.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
void
xml_dump_datatype(hid_t type)
{
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t     curr_pos = 0;        /* total data element position   */

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    ctx.indent_level++;
    dump_indent += COL;

    if(H5Tcommitted(type) > 0) {
        H5O_info_t oinfo;
        obj_t  *found_obj;    /* Found object */

        /* Datatype is a shared or named datatype */
        H5Oget_info(type, &oinfo);
        found_obj = search_obj(type_table, oinfo.addr);

        if(found_obj) {
            /* Shared datatype, must be entered as an object  */
            /* These 2 cases are the same now, but may change */
            char *dtxid = (char *)HDmalloc((size_t)100);

            xml_name_to_XID(found_obj->objname, dtxid, 100, 1);
            if (!found_obj->recorded) {
                /* anonymous stored datatype:
                   following the dumper's current
                   practice:
                   use it's object ref as its name
                 */

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sNamedDataTypePtr OBJ-XID=\"%s\"/>",
                        xmlnsprefix, dtxid);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            } 
            else {
                /* pointer to a named datatype already in XML */
                char *t_objname = xml_escape_the_name(found_obj->objname);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sNamedDataTypePtr OBJ-XID=\"%s\" H5Path=\"%s\" />",
                        xmlnsprefix, dtxid, t_objname);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                HDfree(t_objname);
            }
            HDfree(dtxid);
        } 
        else {
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- h5dump error: unknown committed type. -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        }
    }
    else {
        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sDataType>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level++;
        dump_indent += COL;
        xml_print_datatype(type, 0);
        ctx.indent_level--;
        dump_indent -= COL;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sDataType>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    }
    ctx.indent_level--;
    dump_indent -= COL;

    h5tools_str_close(&buffer);
}

/*-------------------------------------------------------------------------
 * Function:    xml_dump_dataspace
 *
 * Purpose:     Dump description of a dataspace in XML.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
void
xml_dump_dataspace(hid_t space)
{
    hsize_t         size[H5DUMP_MAX_RANK];
    hsize_t         maxsize[H5DUMP_MAX_RANK];
    int             i;
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t     curr_pos = 0;        /* total data element position   */
    
    int             ndims = H5Sget_simple_extent_dims(space, size, maxsize);
    H5S_class_t     space_type = H5Sget_simple_extent_type(space);

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    ctx.indent_level++;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sDataspace>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    ctx.indent_level++;

    switch (space_type) {
    case H5S_SCALAR:
        /* scalar dataspace (just a tag, no XML attrs. defined */

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sScalarDataspace />",xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        break;

    case H5S_SIMPLE:
        /* simple dataspace */
        /* <hdf5:SimpleDataspace Ndims="nd"> */

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sSimpleDataspace Ndims=\"%d\">",xmlnsprefix, ndims);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        /* print the <hdf5:Dimension> elements */
        ctx.indent_level++;
        for (i = 0; i < ndims; i++) {
            if (maxsize[i] == H5S_UNLIMITED) {
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sDimension  DimSize=\"%" H5_PRINTF_LL_WIDTH "u\" MaxDimSize=\"UNLIMITED\"/>",
                        xmlnsprefix,size[i]);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            } 
            else if (maxsize[i] == (hsize_t) 0) {
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sDimension  DimSize=\"%" H5_PRINTF_LL_WIDTH "u\" MaxDimSize=\"%" H5_PRINTF_LL_WIDTH "u\"/>",
                        xmlnsprefix,size[i], size[i]);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            } 
            else {
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sDimension  DimSize=\"%" H5_PRINTF_LL_WIDTH "u\" MaxDimSize=\"%" H5_PRINTF_LL_WIDTH "u\"/>",
                        xmlnsprefix, size[i], maxsize[i]);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            }
        }
        ctx.indent_level--;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sSimpleDataspace>", xmlnsprefix );
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        break;

#ifdef TMP
        /* Commented out: wait until the schema is updated first */
    case H5S_NULL:
        /* null dataspace (just a tag, no XML attrs. defined */

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sNullDataspace />",xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
       break;
#endif /* TMP */

    case H5S_NO_CLASS:
    default:
        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<!-- unknown dataspace -->");
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    }

    ctx.indent_level--;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sDataspace>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    ctx.indent_level--;

    h5tools_str_close(&buffer);
}

/*-------------------------------------------------------------------------
 * Function:    xml_dump_data
 *
 * Purpose:     Dump description of data in XML.
 *              Note that this calls the h5dump_xxx calls in
 *              the h5tools library.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
void
xml_dump_data(hid_t obj_id, int obj_data, struct subset_t UNUSED * sset, int UNUSED pindex)
{
    hid_t               space = -1;
    hid_t               type = -1;
    hid_t               p_type = -1;
    hsize_t             size[64];
    hsize_t             nelmts = 1;
    int                 ndims;
    int                 i;
    int                 status = -1;
    void               *buf = NULL;
    hsize_t             curr_pos = 0;        /* total data element position   */
    h5tools_str_t       buffer;          /* string into which to render   */
    h5tools_context_t   ctx;             /* print context  */
    h5tool_format_t    *outputformat = &xml_dataformat;
    h5tool_format_t     string_dataformat;

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    /* Print all the values. */
    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;
    string_dataformat.cmpd_sep = " ";
    string_dataformat.cmpd_pre = "";
    string_dataformat.cmpd_suf = "";
    string_dataformat.cmpd_end = "";
    string_dataformat.arr_linebreak = 0;
    string_dataformat.arr_pre = "";
    outputformat = &string_dataformat;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
    
    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    ctx.indent_level++;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
    
    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sDataFromFile>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    ctx.indent_level--;
    
    dump_indent += COL;
    ctx.indent_level++;

    if (obj_data == DATASET_DATA) {
        type = H5Dget_type(obj_id);
        if (H5Tget_class(type) == H5T_REFERENCE) {
            status = xml_print_refs(obj_id, DATASET_DATA);
        } 
        else if (H5Tget_class(type) == H5T_STRING) {
            status = xml_print_strs(obj_id, DATASET_DATA);
        } 
        else {
            h5tools_context_t datactx;
            HDmemset(&datactx, 0, sizeof(datactx));
            datactx.need_prefix = TRUE;
            datactx.indent_level = ctx.indent_level;
            datactx.cur_column = ctx.cur_column;
            status = h5tools_dump_dset(rawoutstream, outputformat, &datactx, obj_id, -1, NULL);
        }
    } 
    else {
        /* Attribute data */
        type = H5Aget_type(obj_id);

        if (H5Tget_class(type) == H5T_REFERENCE) {
            /* references are done differently than
               the standard output:
               XML dumps a path to the object
               referenced.
             */
            status = xml_print_refs(obj_id, ATTRIBUTE_DATA);
            H5Tclose(type);
        } 
        else if (H5Tget_class(type) == H5T_STRING) {
            status = xml_print_strs(obj_id, ATTRIBUTE_DATA);
        } 
        else {  /* all other data */
            /* VL data special information */
            unsigned int vl_data = 0; /* contains VL datatypes */
            
            p_type = h5tools_get_native_type(type);

            /* Check if we have VL data in the dataset's datatype */
            if (h5tools_detect_vlen(p_type) == TRUE)
                vl_data = TRUE;

            H5Tclose(type);

            space = H5Aget_space(obj_id);

            ndims = H5Sget_simple_extent_dims(space, size, NULL);

            for (i = 0; i < ndims; i++)
                nelmts *= size[i];

            buf = HDmalloc((size_t)(nelmts * MAX(H5Tget_size(type), H5Tget_size(p_type))));
            HDassert(buf);
            
            if (H5Aread(obj_id, p_type, buf) >= 0) {
                h5tools_context_t datactx;
                HDmemset(&datactx, 0, sizeof(datactx));
                datactx.need_prefix = TRUE;
                datactx.indent_level = ctx.indent_level;
                datactx.cur_column = ctx.cur_column;
                status = h5tools_dump_mem(rawoutstream, outputformat, &datactx, obj_id, p_type, space, buf);
            }
            /* Reclaim any VL memory, if necessary */
            if (vl_data)
                H5Dvlen_reclaim(p_type, space, H5P_DEFAULT, buf);

            HDfree(buf);
            H5Tclose(p_type);
            H5Sclose(space);
            H5Tclose(type);
        }
    }

    if (status == FAIL) {
        ctx.indent_level++;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
        
        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "Unable to print data.");
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        ctx.indent_level--;

        status = 1;
    }
    ctx.indent_level--;
    dump_indent -= COL;

    ctx.indent_level++;

    ctx.need_prefix = TRUE;
    
    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sDataFromFile>",xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    ctx.indent_level--;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
    
    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sData>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    h5tools_str_close(&buffer);
}

/*-------------------------------------------------------------------------
 * Function:    xml_dump_attr
 *
 * Purpose:     Dump a description of an HDF5 attribute in XML.
 *
 * Return:      herr_t
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
xml_dump_attr(hid_t attr, const char *attr_name, const H5A_info_t UNUSED *info,
    void UNUSED * op_data)
{
    hid_t             attr_id = -1;
    hid_t             type = -1;
    hid_t             space = -1;
    H5S_class_t       space_type;
    hsize_t           curr_pos = 0;        /* total data element position   */
    h5tools_str_t     buffer;          /* string into which to render   */
    h5tools_context_t ctx;           /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    
    char *t_aname = xml_escape_the_name(attr_name);

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
    
    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sAttribute Name=\"%s\">", xmlnsprefix, t_aname);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    HDfree(t_aname);

    if ((attr_id = H5Aopen(attr, attr_name, H5P_DEFAULT)) >= 0) {
        type = H5Aget_type(attr_id);
        space = H5Aget_space(attr_id);
        space_type = H5Sget_simple_extent_type(space);

        dump_function_table->dump_dataspace_function(space);
        dump_function_table->dump_datatype_function(type);

        ctx.indent_level++;
        dump_indent += COL;

        if (display_attr_data && space_type != H5S_NULL) {
            switch (H5Tget_class(type)) {
            case H5T_INTEGER:
            case H5T_FLOAT:
            case H5T_STRING:
            case H5T_BITFIELD:
            case H5T_OPAQUE:
            case H5T_ENUM:
            case H5T_ARRAY:
                dump_function_table->dump_data_function(attr_id, ATTRIBUTE_DATA, NULL, 0);
                break;

            case H5T_TIME:
                ctx.indent_level++;
                dump_indent += COL;

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<!-- Time data not yet implemented. -->");
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sNoData/>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<hdf5:Data>");
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "</%sData>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                ctx.indent_level--;
                dump_indent -= COL;
                break;

            case H5T_COMPOUND:
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<!-- Note: format of compound data not specified -->");
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                dump_function_table->dump_data_function(attr_id, ATTRIBUTE_DATA, NULL, 0);
                break;

            case H5T_REFERENCE:
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                if (!H5Tequal(type, H5T_STD_REF_OBJ)) {
                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                    
                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<!-- Note: Region references not supported -->");
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                    
                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sNoData />", xmlnsprefix);
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                }
                else {
                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                    
                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sDataFromFile>", xmlnsprefix);
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                    xml_print_refs(attr_id, ATTRIBUTE_DATA);

                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                    
                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "</%sDataFromFile>", xmlnsprefix);
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                }

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "</%sData>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                break;

            case H5T_VLEN:
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<!-- Note: format of VL data not specified -->");
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                dump_function_table->dump_data_function(attr_id, ATTRIBUTE_DATA, NULL, 0);
                break;
            default:
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<!-- Unknown datatype: %d -->", H5Tget_class(type));
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sNoData/>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "</%sData>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                break;
            }
        }
        else {
            /* The case of an attribute never yet written ??
             * Or dataspace is H5S_NULL. */
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
            
            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
            
            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sNoData/>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.indent_level--;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
            
            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sData>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        }
        ctx.indent_level--;
        dump_indent -= COL;

        H5Tclose(type);
        H5Sclose(space);
        H5Aclose(attr_id);

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
        
        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sAttribute>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        h5tools_str_close(&buffer);
        return SUCCEED;
    }
    else {
        /* ?? failed */
        ctx.indent_level++;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
        
        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<!-- h5dump error: unable to open attribute. -->");
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        ctx.indent_level--;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
        
        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sAttribute>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        h5tools_str_close(&buffer);
        
        h5tools_setstatus(EXIT_FAILURE);
        return FAIL;
    }
}

/*-------------------------------------------------------------------------
 * Function:    xml_dump_named_datatype
 *
 * Purpose:     Dump a description of an HDF5 NDT in XML.
 *
 * Return:      herr_t
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
void
xml_dump_named_datatype(hid_t type, const char *name)
{
    hsize_t           curr_pos = 0;        /* total data element position   */
    h5tools_str_t     buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    char             *tmp;
    char             *dtxid;
    char             *parentxid;
    char             *t_tmp;
    char             *t_prefix;
    char             *t_name;

    tmp = (char *)HDmalloc(HDstrlen(prefix) + HDstrlen(name) + 2);
    HDstrcpy(tmp, prefix);
    HDstrcat(tmp, "/");
    HDstrcat(tmp, name);

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    dtxid = (char *)HDmalloc((size_t)100);
    parentxid = (char *)HDmalloc((size_t)100);
    t_tmp = xml_escape_the_name(tmp);
    t_prefix = xml_escape_the_name(prefix);
    t_name = xml_escape_the_name(name);

    xml_name_to_XID(tmp, dtxid, 100, 1);
    xml_name_to_XID(prefix, parentxid, 100, 1);
    if(HDstrncmp(name, "#", (size_t)1) == 0) {
        /*  Special:  this is an 'anonymous' NDT, deleted but
           still in use.
           We follow the dumper's undocumented practice, and
           use its object id as its name.
           Exactly the same as normal, but a separate case
           in the event we want to do something else in
           the future.
         */

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
        
        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sNamedDataType Name=\"%s\" OBJ-XID=\"%s\" "
                "Parents=\"%s\" H5ParentPaths=\"%s\">",
                xmlnsprefix,
                name, dtxid,
                parentxid, HDstrcmp(prefix,"") ? t_prefix : "/");
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    } 
    else {
        H5O_info_t  oinfo;          /* Object info */

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
        
        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sNamedDataType Name=\"%s\" OBJ-XID=\"%s\" "
                "H5Path=\"%s\" Parents=\"%s\" H5ParentPaths=\"%s\">",
                xmlnsprefix,
                t_name, dtxid,
                t_tmp, parentxid, (HDstrcmp(prefix, "") ? t_prefix : "/"));
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        /* Check uniqueness of named datatype */
        H5Oget_info(type, &oinfo);
        if(oinfo.rc > 1) {
            obj_t       *found_obj;     /* Found object */

            /* Group with more than one link to it... */
            found_obj = search_obj(type_table, oinfo.addr);

            if (found_obj == NULL) {
                indentation(dump_indent);
                error_msg("internal error (file %s:line %d)\n", __FILE__, __LINE__);
                h5tools_setstatus(EXIT_FAILURE);
                goto done;
            } 
            else if(found_obj->displayed) {
                /* We have already printed this named datatype, print it as a
                 * NamedDatatypePtr
                 */
                char pointerxid[100];
                char *t_objname = xml_escape_the_name(found_obj->objname);

                ctx.indent_level++;
                
                xml_name_to_XID(found_obj->objname, pointerxid, (int)sizeof(pointerxid), 1);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sNamedDatatypePtr OBJ-XID=\"%s\" H5Path=\"%s\"/>", xmlnsprefix, pointerxid, t_objname);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                
                ctx.indent_level--;

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
                
                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "</%sNamedDataType>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                HDfree(t_objname);
                goto done;
            } 
            else
                found_obj->displayed = TRUE;
        }
    }

    ctx.indent_level++;
    dump_indent += COL;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
    
    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sDataType>",xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    ctx.indent_level++;
    dump_indent += COL;
    xml_print_datatype(type,1);
    ctx.indent_level--;
    dump_indent -= COL;
    
    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
    
    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sDataType>",xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    ctx.indent_level--;
    dump_indent -= COL;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);
    
    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sNamedDataType>",xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

done:

    h5tools_str_close(&buffer);

    HDfree(dtxid);
    HDfree(parentxid);
    HDfree(t_tmp);
    HDfree(t_prefix);
    HDfree(t_name);
    HDfree(tmp);
}

/*-------------------------------------------------------------------------
 * Function:    xml_dump_group
 *
 * Purpose:     Dump a description of an HDF5 Group (and its members) in XML.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *  Pedro Vicente, October 9, 2007
 *   added parameters to H5A(L)iterate to allow for other iteration orders
 *
 *-------------------------------------------------------------------------
 */
void
xml_dump_group(hid_t gid, const char *name)
{
    H5O_info_t              oinfo;
    hid_t                   gcpl_id;
    hid_t                   dset, type;
    unsigned                crt_order_flags;
    unsigned                attr_crt_order_flags;
    int                     isRoot = 0;
    char                    type_name[1024];
    char                   *t_objname = NULL;
    char                   *par_name = NULL;
    char                   *cp = NULL;
    char                   *tmp = NULL;
    char                   *par = NULL;
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t     curr_pos = 0;        /* total data element position   */

    if ((gcpl_id = H5Gget_create_plist(gid)) < 0) {
        error_msg("error in getting group creation property list ID\n");
        h5tools_setstatus(EXIT_FAILURE);
    }

    /* query the group creation properties for attributes */
    if (H5Pget_attr_creation_order(gcpl_id, &attr_crt_order_flags) < 0) {
        error_msg("error in getting group creation properties\n");
        h5tools_setstatus(EXIT_FAILURE);
    }

    /* query the group creation properties */
    if(H5Pget_link_creation_order(gcpl_id, &crt_order_flags) < 0) {
        error_msg("error in getting group creation properties\n");
        h5tools_setstatus(EXIT_FAILURE);
    }

    if(H5Pclose(gcpl_id) < 0) {
        error_msg("error in closing group creation property list ID\n");
        h5tools_setstatus(EXIT_FAILURE);
    }

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    if(HDstrcmp(name, "/") == 0) {
        isRoot = 1;
        tmp = HDstrdup("/");
    }
    else {
        tmp = (char *)HDmalloc(HDstrlen(prefix) + HDstrlen(name) + 2);
        HDstrcpy(tmp, prefix);
        par = HDstrdup(tmp);
        cp = HDstrrchr(par, '/');
        if(cp) {
            if((cp == par) && HDstrlen(par) > 1)
                *(cp + 1) = '\0';
            else
                *cp = '\0';
        }
    }

    H5Oget_info(gid, &oinfo);

    if(oinfo.rc > 1) {
        obj_t *found_obj;    /* Found object */

        /* Group with more than one link to it... */
        found_obj = search_obj(group_table, oinfo.addr);

        if (found_obj == NULL) {
            indentation(dump_indent);
            error_msg("internal error (file %s:line %d)\n", __FILE__, __LINE__);
            h5tools_setstatus(EXIT_FAILURE);
        }
        else {
            char *t_name = xml_escape_the_name(name);
            char *grpxid = (char *)HDmalloc((size_t)100);
            char *parentxid = (char *)HDmalloc((size_t)100);

            if(found_obj->displayed) {
                char *ptrstr = (char *)HDmalloc((size_t)100);

                /* already seen: enter a groupptr */
                if(isRoot) {
                    /* probably can't happen! */
                    xml_name_to_XID("/", grpxid, 100, 1);

                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sRootGroup OBJ-XID=\"%s\" H5Path=\"%s\">",
                            xmlnsprefix, grpxid, "/");
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                }
                else {
                    t_objname = xml_escape_the_name(found_obj->objname);
                    par_name = xml_escape_the_name(par);
                    xml_name_to_XID(tmp, grpxid, 100, 1);
                    xml_name_to_XID(par, parentxid, 100, 1);

                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sGroup Name=\"%s\" OBJ-XID=\"%s-%d\" H5Path=\"%s\" "
                            "Parents=\"%s\" H5ParentPaths=\"%s\">",
                            xmlnsprefix,t_name, grpxid, get_next_xid(),
                            t_objname, parentxid, par_name);
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                    HDfree(t_objname);
                    HDfree(par_name);
                    
                    ctx.indent_level++;

                    t_objname = xml_escape_the_name(found_obj->objname);/* point to the NDT by name */
                    par_name = xml_escape_the_name(par);
                    xml_name_to_XID(found_obj->objname, ptrstr, 100, 1);
                    xml_name_to_XID(par, parentxid, 100, 1);

                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sGroupPtr OBJ-XID=\"%s\" H5Path=\"%s\" "
                                "Parents=\"%s\" H5ParentPaths=\"%s\" />",
                                xmlnsprefix,
                                ptrstr, t_objname, parentxid, par_name);
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                    
                    ctx.indent_level--;

                    HDfree(t_objname);
                    HDfree(par_name);
                }
                HDfree(ptrstr);
            }
            else {

                /* first time this group has been seen -- describe it  */
                if(isRoot) {
                    xml_name_to_XID("/", grpxid, 100, 1);

                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sRootGroup OBJ-XID=\"%s\" H5Path=\"%s\">",
                            xmlnsprefix, grpxid, "/");
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                }
                else {
                    char *t_tmp = xml_escape_the_name(tmp);

                    par_name = xml_escape_the_name(par);
                    xml_name_to_XID(tmp, grpxid, 100, 1);
                    xml_name_to_XID(par, parentxid, 100, 1);

                    ctx.need_prefix = TRUE;
                    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                    /* Render the element */
                    h5tools_str_reset(&buffer);
                    h5tools_str_append(&buffer, "<%sGroup Name=\"%s\" OBJ-XID=\"%s\" H5Path=\"%s\" "
                            "Parents=\"%s\" H5ParentPaths=\"%s\" >",
                            xmlnsprefix,t_name, grpxid, t_tmp, parentxid, par_name);
                    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                    HDfree(t_tmp);
                    HDfree(par_name);
                }
                found_obj->displayed = TRUE;

                /* 1.  do all the attributes of the group */
                
                ctx.indent_level++;
                dump_indent += COL;

                if((sort_by == H5_INDEX_CRT_ORDER) && (attr_crt_order_flags & H5P_CRT_ORDER_TRACKED)) {
                    if(H5Aiterate2(gid, sort_by, sort_order, NULL, dump_function_table->dump_attribute_function, NULL) < 0) {
                        error_msg("error getting attribute information\n");
                        h5tools_setstatus(EXIT_FAILURE);
                    } /* end if */
                } /* end if */
                else {
                    if(H5Aiterate2(gid, H5_INDEX_NAME, sort_order, NULL, dump_function_table->dump_attribute_function, NULL) < 0) {
                        error_msg("error getting attribute information\n");
                        h5tools_setstatus(EXIT_FAILURE);
                    } /* end if */
                } /* end else */

                if(isRoot && unamedtype) {
                    unsigned u;

                    /* Very special case: dump unamed type in root group */
                    for(u = 0; u < type_table->nobjs; u++) {
                        if(!type_table->objs[u].recorded) {
                            dset = H5Dopen2(gid, type_table->objs[u].objname, H5P_DEFAULT);
                            type = H5Dget_type(dset);
                            sprintf(type_name, "#"H5_PRINTF_HADDR_FMT, type_table->objs[u].objno);
                            dump_function_table->dump_named_datatype_function(type, type_name);
                            H5Tclose(type);
                            H5Dclose(dset);
                        }
                    }
                }

                /* iterate through all the links */

                if((sort_by == H5_INDEX_CRT_ORDER) && (crt_order_flags & H5P_CRT_ORDER_TRACKED))
                    H5Literate(gid, sort_by, sort_order, NULL, xml_dump_all_cb, NULL);
                else
                    H5Literate(gid, H5_INDEX_NAME, sort_order, NULL, xml_dump_all_cb, NULL);

                dump_indent -= COL;
                ctx.indent_level--;
            }
            HDfree(t_name);
            HDfree(grpxid);
            HDfree(parentxid);
        }
    }
    else {
        /* only link -- must be first time! */
        char *t_name = xml_escape_the_name(name);
        char *grpxid = (char *)HDmalloc((size_t)100);
        char *parentxid = (char *)HDmalloc((size_t)100);

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);

        if(isRoot) {
            xml_name_to_XID("/", grpxid, 100, 1);
            h5tools_str_append(&buffer, "<%sRootGroup OBJ-XID=\"%s\" H5Path=\"%s\">", xmlnsprefix, grpxid, "/");
        }
        else {
            char *t_tmp = xml_escape_the_name(tmp);

            par_name = xml_escape_the_name(par);
            xml_name_to_XID(tmp, grpxid, 100, 1);
            xml_name_to_XID(par, parentxid, 100, 1);
            h5tools_str_append(&buffer, "<%sGroup Name=\"%s\" OBJ-XID=\"%s\" H5Path=\"%s\" "
                    "Parents=\"%s\" H5ParentPaths=\"%s\" >",
                    xmlnsprefix, t_name, grpxid, t_tmp, parentxid, par_name);
            HDfree(t_tmp);
            HDfree(par_name);
        }
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        HDfree(t_name);
        HDfree(grpxid);
        HDfree(parentxid);

        /* 1.  do all the attributes of the group */
        
        ctx.indent_level++;
        dump_indent += COL;

        if((sort_by == H5_INDEX_CRT_ORDER) && (attr_crt_order_flags & H5P_CRT_ORDER_TRACKED)) {
            if(H5Aiterate2(gid, sort_by, sort_order, NULL, dump_function_table->dump_attribute_function, NULL) < 0) {
                error_msg("error getting attribute information\n");
                h5tools_setstatus(EXIT_FAILURE);
            } /* end if */
        } /* end if */
        else {
            if(H5Aiterate2(gid, H5_INDEX_NAME, sort_order, NULL, dump_function_table->dump_attribute_function, NULL) < 0) {
                error_msg("error getting attribute information\n");
                h5tools_setstatus(EXIT_FAILURE);
            } /* end if */
        } /* end else */

        if(isRoot && unamedtype) {
            unsigned u;

            /* Very special case: dump unamed type in root group */
            for(u = 0; u < type_table->nobjs; u++) {
                if(!type_table->objs[u].recorded) {
                    dset = H5Dopen2(gid, type_table->objs[u].objname, H5P_DEFAULT);
                    type = H5Dget_type(dset);
                    sprintf(type_name, "#"H5_PRINTF_HADDR_FMT, type_table->objs[u].objno);
                    dump_function_table->dump_named_datatype_function(type, type_name);
                    H5Tclose(type);
                    H5Dclose(dset);
                }
            }
        }

        /* iterate through all the links */

        if((sort_by == H5_INDEX_CRT_ORDER) && (crt_order_flags & H5P_CRT_ORDER_TRACKED))
            H5Literate(gid, sort_by, sort_order, NULL, xml_dump_all_cb, NULL);
        else
            H5Literate(gid, H5_INDEX_NAME, sort_order, NULL, xml_dump_all_cb, NULL);

        dump_indent -= COL;
        ctx.indent_level--;
    }

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    if(isRoot)
        h5tools_str_append(&buffer, "</%sRootGroup>", xmlnsprefix);
    else
        h5tools_str_append(&buffer, "</%sGroup>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    h5tools_str_close(&buffer);
    
    if(par)
        HDfree(par);
    if(tmp)
        HDfree(tmp);
}

/*-------------------------------------------------------------------------
 * Function:    xml_print_refs
 *
 * Purpose:     Print a path to the objects referenced by HDF5 Referneces.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static int
xml_print_refs(hid_t did, int source)
{
    herr_t      e;
    hid_t       type;
    hid_t       space;
    hssize_t    ssiz;
    hsize_t     i;
    size_t      tsiz;
    hobj_ref_t *refbuf = NULL;
    char       *buf = NULL;
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t     curr_pos = 0;        /* total data element position   */

    if (source == DATASET_DATA) {
        type = H5Dget_type(did);
    }
    else if (source == ATTRIBUTE_DATA) {
        type = H5Aget_type(did);
    }
    else {
        /* return an error */
        return FAIL;
    }
    if (H5Tget_class(type) != H5T_REFERENCE) {
        /* return an error */
        goto error;
    }
    if (!H5Tequal(type, H5T_STD_REF_OBJ)) {
        /* region ref not supported yet... */
        /* return an error */
        goto error;
    }
    if (source == DATASET_DATA) {
        space = H5Dget_space(did);
        if ((ssiz = H5Sget_simple_extent_npoints(space)) < 0)
            goto error;
        if ((tsiz = H5Tget_size(type)) == 0)
            goto error;

        buf = (char *) HDcalloc((size_t)(ssiz * tsiz), sizeof(char));
        if (buf == NULL)
            goto error;
        e = H5Dread(did, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf);
        /* need to check result here */
        if (e < 0) {
            goto error;
        }
    }
    else if (source == ATTRIBUTE_DATA) {
        space = H5Aget_space(did);
        if ((ssiz = H5Sget_simple_extent_npoints(space)) < 0)
            goto error;
        if ((tsiz = H5Tget_size(type)) == 0)
            goto error;

        buf = (char *) HDcalloc((size_t)(ssiz * tsiz), sizeof(char));
        if (buf == NULL) {
            goto error;
        }
        e = H5Aread(did, H5T_STD_REF_OBJ, buf);
        /* need to check the result here */
        if (e < 0) {
            goto error;
        }
    }

    refbuf = (hobj_ref_t *) buf;

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    for (i = 0; i < (hsize_t)ssiz; i++) {
        const char *path = lookup_ref_path(*refbuf);
        ctx.indent_level++;

        if (!path) {
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "\"%s\"", "NULL");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        }
        else {
            char *t_path = xml_escape_the_string(path, -1);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "\"%s\"", t_path);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            HDfree(t_path);
        }
        ctx.indent_level--;

        refbuf++;
    }

    h5tools_str_close(&buffer);

    HDfree(buf);
    H5Tclose(type);
    H5Sclose(space);
    return SUCCEED;
    
error:
    if(buf)
        HDfree(buf);

    H5E_BEGIN_TRY {
        H5Tclose(type);
        H5Sclose(space);
    } H5E_END_TRY;
    return FAIL;
}

/*-------------------------------------------------------------------------
 * Function:    xml_print_strs
 *
 * Purpose:     Print strings.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static int
xml_print_strs(hid_t did, int source)
{
    herr_t      e;
    hid_t       type;
    hid_t       space;
    hssize_t    ssiz;
    htri_t      is_vlstr = FALSE;
    size_t      tsiz;
    size_t      i;
    size_t      str_size = 0;
    char       *bp = NULL;
    char       *onestring = NULL;
    void       *buf = NULL;
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t     curr_pos = 0;        /* total data element position   */

    if (source == DATASET_DATA) {
        type = H5Dget_type(did);
    }
    else if (source == ATTRIBUTE_DATA) {
        type = H5Aget_type(did);
    }
    else {
        /* return an error */
        return FAIL;
    }
    if (H5Tget_class(type) != H5T_STRING) {
        /* return an error */
        goto error;
    }
    /* Check if we have VL data in the dataset's datatype */
    is_vlstr = H5Tis_variable_str(type);

    if (source == DATASET_DATA) {
        space = H5Dget_space(did);
        if((ssiz = H5Sget_simple_extent_npoints(space)) < 0)
            goto error;
        if((tsiz = H5Tget_size(type)) == 0)
            goto error;

        buf = HDmalloc((size_t)(ssiz * tsiz));
        if (buf == NULL)
            goto error;

        e = H5Dread(did, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf);
        if (e < 0) {
            goto error;
        }
    }
    else if (source == ATTRIBUTE_DATA) {
        space = H5Aget_space(did);
        if((ssiz = H5Sget_simple_extent_npoints(space)) < 0)
            goto error;
        if((tsiz = H5Tget_size(type)) == 0)
            goto error;

        buf = HDmalloc((size_t)(ssiz * tsiz));
        if (buf == NULL)
            goto error;

        e = H5Aread(did, type, buf);
        if (e < 0) {
            goto error;
        }
    }

    bp = (char*) buf;
    if (!is_vlstr)
        onestring = (char *) HDcalloc(tsiz, sizeof(char));

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    for (i = 0; i < ssiz; i++) {
        if (is_vlstr) {
            onestring = *(char **) bp;
            if (onestring)
                str_size = (size_t) HDstrlen(onestring);
        }
        else {
            HDstrncpy(onestring, bp, tsiz);
            str_size = tsiz;
        }

        if (!onestring) {
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "NULL");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        }
        else {
            char *t_onestring = xml_escape_the_string(onestring, (int) str_size);
            if (t_onestring) {
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "\"%s\"", t_onestring);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
                HDfree(t_onestring);
            }
        }
        bp += tsiz;
    }

    h5tools_str_close(&buffer);

    /* Reclaim any VL memory, if necessary */
    if (!is_vlstr)
        if (onestring)
            HDfree(onestring);
    if (buf) {
        if (is_vlstr)
            H5Dvlen_reclaim(type, space, H5P_DEFAULT, buf);
        HDfree(buf);
    }
    H5Tclose(type);
    H5Sclose(space);
    return SUCCEED;
    
error:
    if(buf)
        HDfree(buf);

    H5E_BEGIN_TRY {
        H5Tclose(type);
        H5Sclose(space);
    } H5E_END_TRY;
    return FAIL;
}

/*-------------------------------------------------------------------------
 * Function:    check_filters
 *
 * Purpose:     private function to check for the filters and
 *              put tags in the XML.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static void
check_filters(hid_t dcpl)
{
    int             nfilt;
    int             i;
    H5Z_filter_t    filter;
    char            namebuf[120];
    size_t          cd_nelmts = 20;
    unsigned int    cd_values[20];
    unsigned int    flags;
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t     curr_pos = 0;        /* total data element position   */

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    nfilt = H5Pget_nfilters(dcpl);
    if (nfilt <= 0)
        return;
    for (i = 0; i < nfilt; i++) {
        filter = H5Pget_filter2(dcpl, (unsigned) i, &flags, (size_t *) &cd_nelmts, cd_values, (size_t)120, namebuf, NULL);
        if (filter == H5Z_FILTER_DEFLATE) {
            ctx.indent_level++;
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sDeflate Level=\"", xmlnsprefix);
            if (cd_nelmts < 1) {
                /* not sure what this means? */
                h5tools_str_append(&buffer, "6");
            }
            else {
                h5tools_str_append(&buffer, "%d", cd_values[0]);
            }
            h5tools_str_append(&buffer, "\"/>");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;
        }
        else if (filter == H5Z_FILTER_FLETCHER32) {
            ctx.indent_level++;
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sFletcher32 />", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;
        }
        else if (filter == H5Z_FILTER_SHUFFLE) {
            ctx.indent_level++;
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sShuffle />", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;
        }
        else if (filter == H5Z_FILTER_SZIP) {
            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sSZIP ", xmlnsprefix);
            if (cd_nelmts < 2) {
                /* no pixels ? */
                h5tools_str_append(&buffer, "Pixels_per_block=\"-1\" ");
            }
            else {
                h5tools_str_append(&buffer, "Pixels_per_block=\"%d\" ", cd_values[1]);
            }
            /* analyse the options mask */
            if (cd_values[0] & H5_SZIP_CHIP_OPTION_MASK) {
                h5tools_str_append(&buffer, "Mode =\"Hardware\" ");
            }
            else if (cd_values[0] & H5_SZIP_ALLOW_K13_OPTION_MASK) {
                h5tools_str_append(&buffer, "Mode =\"K13\" ");
            }
            h5tools_str_append(&buffer, "Coding=\"");
            if (cd_values[0] & H5_SZIP_EC_OPTION_MASK) {
                h5tools_str_append(&buffer, "Entropy");
            }
            else if (cd_values[0] & H5_SZIP_NN_OPTION_MASK) {
                h5tools_str_append(&buffer, "NN");
            }
            h5tools_str_append(&buffer, "\" ");

            h5tools_str_append(&buffer, "ByteOrder=\"");
            if (cd_values[0] & H5_SZIP_LSB_OPTION_MASK) {
                h5tools_str_append(&buffer, "LSB");
            }
            else if (cd_values[0] & H5_SZIP_MSB_OPTION_MASK) {
                h5tools_str_append(&buffer, "MSB");
            }
            h5tools_str_append(&buffer, "\" ");

            if (cd_values[0] & H5_SZIP_RAW_OPTION_MASK) {
                h5tools_str_append(&buffer, "Header=\"Raw\"");
            }
            h5tools_str_append(&buffer, "/>");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level--;
        }
        else {
            /* unknown option */
        }
    }

    h5tools_str_close(&buffer);
}

static void
xml_dump_fill_value(hid_t dcpl, hid_t type)
{
    size_t      sz;
    size_t      i;
    hsize_t     space;
    void       *buf;
    char       *name;
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t           curr_pos = 0;        /* total data element position   */

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else 
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    ctx.indent_level++;
    dump_indent += COL;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    ctx.indent_level++;
    dump_indent += COL;

    space = H5Tget_size(type);
    buf = HDmalloc((size_t) space);

    H5Pget_fill_value(dcpl, type, buf);

    if (H5Tget_class(type) == H5T_REFERENCE) {
        const char * path = lookup_ref_path(*(hobj_ref_t *) buf);

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sDataFromFile>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        if (!path) {
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "\"%s\"", "NULL");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        }
        else {
            char *t_path = xml_escape_the_string(path, -1);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "\"%s\"", t_path);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            HDfree(t_path);
        }

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sDataFromFile>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    }
    else if (H5Tget_class(type) == H5T_STRING) {
        /* ????? */
        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<!-- String fill values not yet implemented. -->");
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sNoData />", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    }
    else {
        /* all other data */
        switch (H5Tget_class(type)) {
        case H5T_INTEGER:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sDataFromFile>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "\"%d\"", *(int *) buf);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sDataFromFile>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        case H5T_FLOAT:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sDataFromFile>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "\"%f\"", *(float *) buf);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sDataFromFile>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        case H5T_BITFIELD:
        case H5T_OPAQUE:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sDataFromFile>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            sz = H5Tget_size(type);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "\"");
            for (i = 0; i < sz; i++) {
                h5tools_str_append(&buffer, "%x ", *(unsigned int *) buf);
                buf = (char *) buf + sizeof(unsigned int);
            }
            h5tools_str_append(&buffer, "\"");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sDataFromFile>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        case H5T_ENUM:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sDataFromFile>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            name = H5Tget_member_name(type, *(unsigned *) buf);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "\"%s\"", name);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            if(name)
                H5free_memory(name);
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sDataFromFile>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        case H5T_ARRAY:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- Array fill values not yet implemented. -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sNoData />", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        case H5T_TIME:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- Time fill not yet implemented. -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sNoData />", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        case H5T_COMPOUND:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- Compound fill not yet implemented. -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sNoData />", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        case H5T_VLEN:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- VL fill not yet implemented. -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sNoData />", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        default:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- Unknown fill datatype: %d -->", H5Tget_class(type));
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sNoData/>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        }
    }
    HDfree(buf);
    ctx.indent_level--;
    dump_indent -= COL;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sData>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    ctx.indent_level--;
    dump_indent -= COL;

    h5tools_str_close(&buffer);
}

/*-------------------------------------------------------------------------
 * Function:    xml_dump_dataset
 *
 * Purpose:     Dump a description of an HDF5 dataset in XML.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *  Pedro Vicente, October 9, 2007
 *   added parameters to H5Aiterate2 to allow for other iteration orders
 *
 *-------------------------------------------------------------------------
 */
void
xml_dump_dataset(hid_t did, const char *name, struct subset_t UNUSED * sset)
{
    hid_t               type;
    hid_t               space;
    hid_t               dcpl;
    H5D_fill_value_t    fvstatus;
    int                 maxdims;
    hsize_t            *chsize;
    int                 ndims;
    int                 i;
    H5D_alloc_time_t    at;
    H5D_fill_time_t     ft;
    hsize_t             tempi;
    char               *tmp;
    char               *t_name;
    char               *t_tmp;
    char               *t_prefix;
    unsigned            attr_crt_order_flags;
    h5tools_str_t       buffer;          /* string into which to render   */
    h5tools_context_t   ctx;            /* print context  */
    h5tool_format_t    *outputformat = &xml_dataformat;
    h5tool_format_t     string_dataformat;
    hsize_t             curr_pos = 0;        /* total data element position   */
    
    char *rstr = (char*) HDmalloc((size_t)100);
    char *pstr = (char*) HDmalloc((size_t)100);

    tmp = (char*) HDmalloc(HDstrlen(prefix) + HDstrlen(name) + 2);
    HDstrcpy(tmp, prefix);
    HDstrcat(tmp, "/");
    HDstrcat(tmp, name);

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;

    t_name = xml_escape_the_name(name);
    t_tmp = xml_escape_the_name(tmp);
    t_prefix = xml_escape_the_name(prefix);
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    xml_name_to_XID(tmp, rstr, 100, 1);
    xml_name_to_XID(prefix, pstr, 100, 1);

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sDataset Name=\"%s\" OBJ-XID=\"%s\" H5Path= \"%s\" Parents=\"%s\" H5ParentPaths=\"%s\">",
            xmlnsprefix, t_name, rstr, t_tmp, pstr,
            strcmp(prefix, "") ? t_prefix : "/");
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    HDfree(t_name);
    HDfree(t_tmp);
    HDfree(t_prefix);
    HDfree(rstr);
    HDfree(pstr);
    HDfree(tmp);

    dcpl = H5Dget_create_plist(did);
    type = H5Dget_type(did);
    space = H5Dget_space(did);

    /* query the creation properties for attributes */
    H5Pget_attr_creation_order(dcpl, &attr_crt_order_flags);

    /* Print information about storage layout */
    if (H5D_CHUNKED == H5Pget_layout(dcpl)) {
        maxdims = H5Sget_simple_extent_ndims(space);
        HDassert(maxdims >= 0);
        chsize = (hsize_t *)HDmalloc((size_t)maxdims * sizeof(hsize_t));
        ctx.indent_level++;
        dump_indent += COL;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sStorageLayout>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level++;
        dump_indent += COL;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sChunkedLayout ", xmlnsprefix);
        ndims = H5Pget_chunk(dcpl, maxdims, chsize);
        h5tools_str_append(&buffer, "Ndims=\"%d\">", ndims);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        ctx.indent_level++;
        dump_indent += COL;

        for (i = 0; i < ndims; i++) {

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sChunkDimension DimSize=\"%" H5_PRINTF_LL_WIDTH "u\" />", xmlnsprefix, chsize[i]);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        }

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sRequiredFilter>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        ctx.indent_level++;
        dump_indent += COL;
        check_filters(dcpl);
        ctx.indent_level--;
        dump_indent -= COL;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sRequiredFilter>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        ctx.indent_level--;
        dump_indent -= COL;
        
        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sChunkedLayout>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;
        dump_indent -= COL;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sStorageLayout>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;
        dump_indent -= COL;
        HDfree(chsize);
    }
    else if (H5D_CONTIGUOUS == H5Pget_layout(dcpl)) {
        ctx.indent_level++;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sStorageLayout>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level++;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sContiguousLayout/>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sStorageLayout>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;
    }
    else if (H5D_COMPACT == H5Pget_layout(dcpl)) {
        ctx.indent_level++;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sStorageLayout>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level++;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sCompactLayout/>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sStorageLayout>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;
    }
    /* and check for external.... ?? */

    /* fill value */

    ctx.indent_level++;
    dump_indent += COL;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sFillValueInfo ", xmlnsprefix);
    H5Pget_fill_time(dcpl, &ft);
    h5tools_str_append(&buffer, "FillTime=\"");
    switch (ft) {
    case H5D_FILL_TIME_ALLOC:
        h5tools_str_append(&buffer, "FillOnAlloc");
        break;
    case H5D_FILL_TIME_NEVER:
        h5tools_str_append(&buffer, "FillNever");
        break;
    case H5D_FILL_TIME_IFSET:
        h5tools_str_append(&buffer, "FillIfSet");
        break;
    default:
        h5tools_str_append(&buffer, "?");
        break;
    }
    h5tools_str_append(&buffer, "\" ");
    H5Pget_alloc_time(dcpl, &at);
    h5tools_str_append(&buffer, "AllocationTime=\"");
    switch (at) {
    case H5D_ALLOC_TIME_EARLY:
        h5tools_str_append(&buffer, "Early");
        break;
    case H5D_ALLOC_TIME_INCR:
        h5tools_str_append(&buffer, "Incremental");
        break;
    case H5D_ALLOC_TIME_LATE:
        h5tools_str_append(&buffer, "Late");
        break;
    case H5D_ALLOC_TIME_DEFAULT:
    default:
        h5tools_str_append(&buffer, "?");
        break;
    }
    h5tools_str_append(&buffer, "\"");
    h5tools_str_append(&buffer, ">");
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    ctx.indent_level++;
    dump_indent += COL;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sFillValue>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    H5Pfill_value_defined(dcpl, &fvstatus);
    if (fvstatus == H5D_FILL_VALUE_UNDEFINED || (fvstatus == H5D_FILL_VALUE_DEFAULT && ft == H5D_FILL_TIME_IFSET)) {
        ctx.indent_level++;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sNoFill/>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;
    }
    else {
        xml_dump_fill_value(dcpl, type);
    }

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sFillValue>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    ctx.indent_level--;
    dump_indent -= COL;

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sFillValueInfo>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    ctx.indent_level--;
    dump_indent -= COL;

    dump_function_table->dump_dataspace_function(space);
    dump_function_table->dump_datatype_function(type);

    ctx.indent_level++;
    dump_indent += COL;

    if ((sort_by == H5_INDEX_CRT_ORDER) && (attr_crt_order_flags & H5P_CRT_ORDER_TRACKED)) {
        if (H5Aiterate2(did, sort_by, sort_order, NULL, dump_function_table->dump_attribute_function, NULL) < 0) {
            error_msg("error getting attribute information\n");
            h5tools_setstatus(EXIT_FAILURE);
        } /* end if */
    } /* end if */
    else {
        if (H5Aiterate2(did, H5_INDEX_NAME, sort_order, NULL, dump_function_table->dump_attribute_function, NULL) < 0) {
            error_msg("error getting attribute information\n");
            h5tools_setstatus(EXIT_FAILURE);
        } /* end if */
    } /* end else */

    ctx.indent_level--;
    dump_indent -= COL;
    tempi = H5Dget_storage_size(did);

    if (display_data && (tempi > 0)) {
        switch (H5Tget_class(type)) {
        case H5T_INTEGER:
        case H5T_FLOAT:
        case H5T_STRING:
        case H5T_BITFIELD:
        case H5T_OPAQUE:
        case H5T_ENUM:
        case H5T_ARRAY:
            ctx.indent_level++;
            dump_indent += COL;
            dump_function_table->dump_data_function(did, DATASET_DATA, NULL, 0);
            ctx.indent_level--;
            dump_indent -= COL;
            break;

        case H5T_TIME:
            ctx.indent_level++;

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- Time data not yet implemented. -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sNoData />", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.indent_level--;
            break;

        case H5T_COMPOUND:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- Note: format of compound data not specified -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.indent_level++;
            dump_indent += COL;
            dump_function_table->dump_data_function(did, DATASET_DATA, NULL, 0);
            ctx.indent_level--;
            dump_indent -= COL;
            break;

        case H5T_REFERENCE:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            if (!H5Tequal(type, H5T_STD_REF_OBJ)) {
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<!-- Note: Region references not supported -->");
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sNoData />", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            }
            else {
                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "<%sDataFromFile>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

                xml_print_refs(did, DATASET_DATA);

                ctx.need_prefix = TRUE;
                h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

                /* Render the element */
                h5tools_str_reset(&buffer);
                h5tools_str_append(&buffer, "</%sDataFromFile>", xmlnsprefix);
                h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            }

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sData>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;

        case H5T_VLEN:
            ctx.indent_level--;
            dump_indent -= COL;
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- Note: format of VL data not specified -->");
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            ctx.indent_level++;
            dump_indent += COL;

            ctx.indent_level++;
            dump_indent += COL;
            dump_function_table->dump_data_function(did, DATASET_DATA, NULL, 0);
            ctx.indent_level--;
            dump_indent -= COL;
            break;
        default:
            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<!-- Unknown datatype: %d -->", H5Tget_class(type));
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "<%sNoData/>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

            ctx.need_prefix = TRUE;
            h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

            /* Render the element */
            h5tools_str_reset(&buffer);
            h5tools_str_append(&buffer, "</%sData>", xmlnsprefix);
            h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
            break;
        }
    }
    else {
        /* no data written */
        ctx.indent_level++;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sData>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level++;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sNoData/>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sData>", xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;
    }

    H5Tclose(type);
    H5Sclose(space);
    H5Pclose(dcpl);

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sDataset>", xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    h5tools_str_close(&buffer);
}

/*-------------------------------------------------------------------------
 * Function:    xml_print_enum
 *
 * Purpose:     Print the values of an HDF5 ENUM in XML.
 *              Very similar to regular DDL output.
 *
 * Return:      void
 *
 * Programmer:  REMcG
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static void
xml_print_enum(hid_t type)
{
    char              **name = NULL;    /*member names                   */
    unsigned char      *value = NULL;   /*value array                    */
    unsigned            nmembs;         /*number of members              */
    hid_t               super;          /*enum base integer type         */
    hid_t               native = -1;    /*native integer datatype        */
    size_t              dst_size;       /*destination value type size    */
    unsigned            i;              /*miscellaneous counters         */
    size_t              j;
    h5tools_str_t buffer;          /* string into which to render   */
    h5tools_context_t ctx;            /* print context  */
    h5tool_format_t  *outputformat = &xml_dataformat;
    h5tool_format_t   string_dataformat;
    hsize_t     curr_pos = 0;        /* total data element position   */

    /* setup */
    HDmemset(&buffer, 0, sizeof(h5tools_str_t));

    HDmemset(&ctx, 0, sizeof(ctx));
    ctx.indent_level = dump_indent/COL;
    ctx.cur_column = dump_indent;
    
    string_dataformat = *outputformat;

    if (fp_format) {
        string_dataformat.fmt_double = fp_format;
        string_dataformat.fmt_float = fp_format;
    }

    if (h5tools_nCols==0) {
        string_dataformat.line_ncols = 65535;
        string_dataformat.line_per_line = 1;
    }
    else
        string_dataformat.line_ncols = h5tools_nCols;

    string_dataformat.do_escape = display_escape;
    outputformat = &string_dataformat;

    nmembs = (unsigned)H5Tget_nmembers(type);
    super = H5Tget_super(type);

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "<%sDataType>",xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    xml_print_datatype(super,0);

    ctx.need_prefix = TRUE;
    h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

    /* Render the element */
    h5tools_str_reset(&buffer);
    h5tools_str_append(&buffer, "</%sDataType>",xmlnsprefix);
    h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

    /*
     * Determine what datatype to use for the native values.  To simplify
     * things we entertain three possibilities:
     *  1. long long -- the largest native signed integer
     *    2. unsigned long long -- the largest native unsigned integer
     *    3. raw format
     */
    if (H5Tget_size(type) <= sizeof(long long)) {
        dst_size = sizeof(long long);

        if (H5T_SGN_NONE == H5Tget_sign(type)) {
            native = H5T_NATIVE_ULLONG;
        } 
        else {
            native = H5T_NATIVE_LLONG;
        }
    } 
    else {
        dst_size = H5Tget_size(type);
    }

    /* Get the names and raw values of all members */
    name = (char **)HDcalloc((size_t)nmembs, sizeof(char *));
    value = (unsigned char *)HDcalloc((size_t)nmembs, MAX(H5Tget_size(type), dst_size));

    for (i = 0; i < nmembs; i++) {
        name[i] = H5Tget_member_name(type, i);
        H5Tget_member_value(type, i, value + i * H5Tget_size(type));
    }

    /* Convert values to native datatype */
    if (native > 0)
        H5Tconvert(super, native, (size_t)nmembs, value, NULL, H5P_DEFAULT);

    /* Sort members by increasing value */
    /*not implemented yet */

    /* Print members */
    ctx.indent_level++;
    dump_indent += COL;
    for (i = 0; i < nmembs; i++) {
        char *t_name = xml_escape_the_name(name[i]);

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sEnumElement>",xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level++;
        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "%s", t_name);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        HDfree(t_name);
        ctx.indent_level--;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sEnumElement>",xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "<%sEnumValue>",xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level++;
        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        if (native < 0) {
            h5tools_str_append(&buffer, "0x");

            for (j = 0; j < dst_size; j++)
                h5tools_str_append(&buffer, "%02x", value[i * dst_size + j]);
        } 
        else if (H5T_SGN_NONE == H5Tget_sign(native)) {
            h5tools_str_append(&buffer,"%" H5_PRINTF_LL_WIDTH "u", *((unsigned long long *)
                       ((void *) (value + i * dst_size))));
        } 
        else {
            h5tools_str_append(&buffer,"%" H5_PRINTF_LL_WIDTH "d",
                      *((long long *) ((void *) (value + i * dst_size))));
        }
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
        ctx.indent_level--;

        ctx.need_prefix = TRUE;
        h5tools_simple_prefix(rawoutstream, outputformat, &ctx, (hsize_t)0, 0);

        /* Render the element */
        h5tools_str_reset(&buffer);
        h5tools_str_append(&buffer, "</%sEnumValue>",xmlnsprefix);
        h5tools_render_element(rawoutstream, outputformat, &ctx, &buffer, &curr_pos, (size_t)outputformat->line_ncols, (hsize_t)0, (hsize_t)0);
    }
    ctx.indent_level--;
    dump_indent -= COL;

    h5tools_str_close(&buffer);

    /* Release resources */
    for (i = 0; i < nmembs; i++)
        H5free_memory(name[i]);

    HDfree(name);
    HDfree(value);
    H5Tclose(super);
}

